package jwt

import (
	"errors"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
)

const (
	mySigningKey = "Darkling I listen; And for many a time I have been half in love with easeful death."
)

func newToken(claims jwt.MapClaims) (string, error) {
	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims = claims
	tokenString, err := token.SignedString([]byte(mySigningKey))
	return tokenString, err
}

// NewToken 生成一个携带用户uuid信息、过期时间为1小时的jwt token
func NewToken(uuid string) (string, error) {
	token := jwt.New(jwt.SigningMethodHS256)
	claims := make(jwt.MapClaims)
	claims["uuid"] = uuid
	claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
	token.Claims = claims
	tokenString, err := token.SignedString([]byte(mySigningKey))
	return tokenString, err
}

// ParseToken 解码token，得到用户信息 uuid
// 过期的token会报错
func ParseToken(myToken string) (uuid string, err error) {
	token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
		return []byte(mySigningKey), nil
	})

	if err != nil {
		return
	}

	claims := token.Claims.(jwt.MapClaims)
	uuid = claims["uuid"].(string)

	if err == nil && !token.Valid {
		err = errors.New("Token Invalid")
	}

	return
}

// NewCaptchaToken 图形验证码的token
func NewCaptchaToken(cap string) (string, error) {
	claims := make(jwt.MapClaims)
	claims["cap"] = cap
	claims["exp"] = time.Now().Add(time.Second * 20).Unix()
	return newToken(claims)
}

// ParseCaptchaToken 解码图形验证码的token
func ParseCaptchaToken(myToken string) (cap string, err error) {
	token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
		return []byte(mySigningKey), nil
	})

	if err != nil {
		return
	}

	claims := token.Claims.(jwt.MapClaims)
	cap = claims["cap"].(string)

	if cap == "" {
		err = errors.New("Token Invalid")
		return
	}

	if err == nil && !token.Valid {
		err = errors.New("Token Invalid")
		return
	}

	return
}

// NewMobileCodeToken 手机验证码的token
func NewMobileCodeToken(code string, mobile string) (string, error) {
	claims := make(jwt.MapClaims)
	claims["code"] = code
	claims["mobile"] = mobile
	claims["exp"] = time.Now().Add(time.Minute * 1).Unix()
	return newToken(claims)
}

// ParseMobileCodeToken 解码手机验证码token
func ParseMobileCodeToken(myToken string) (mobile string, code string, err error) {
	token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
		return []byte(mySigningKey), nil
	})

	if err != nil {
		return
	}

	claims := token.Claims.(jwt.MapClaims)
	mobile = claims["mobile"].(string)
	code = claims["code"].(string)

	if mobile == "" || code == "" {
		err = errors.New("Token Invalid")
		return
	}

	if err == nil && !token.Valid {
		err = errors.New("Token Invalid")
		return
	}

	return
}
